package com.example.mycomposelearing.custom

import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.SizeTransform
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.AnimationVector2D
import androidx.compose.animation.core.CubicBezierEasing
import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.TargetBasedAnimation
import androidx.compose.animation.core.TwoWayConverter
import androidx.compose.animation.core.VectorConverter
import androidx.compose.animation.core.animateDp
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.animateValueAsState
import androidx.compose.animation.core.calculateTargetValue
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.keyframes
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import androidx.compose.animation.core.updateTransition
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.splineBasedDecay
import androidx.compose.animation.with
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.gestures.horizontalDrag
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.withFrameNanos
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.graphics.asAndroidBitmap
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.input.pointer.positionChange
import androidx.compose.ui.input.pointer.util.VelocityTracker
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.res.imageResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.unit.toSize
import com.example.mycomposelearing.R
import com.example.mycomposelearing.custom.CustomImageMainActivity.Companion.TAG
import com.example.mycomposelearing.custom.ui.AnimatedShimmerItem
import com.example.mycomposelearing.custom.ui.ShowCollectClickAnimationButton
import com.example.mycomposelearing.custom.ui.SpringDemo
import com.example.mycomposelearing.custom.ui.WaveConfig
import com.example.mycomposelearing.custom.ui.WaveLoading
import com.example.mycomposelearing.custom.ui.spacerPadding
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlin.math.absoluteValue
import kotlin.math.roundToInt

class CustomImageMainActivity : ComponentActivity() {
    companion object{
          const val TAG = "CustomImageMainActivity"
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            // A surface container using the 'background' color from the theme
            Surface(
                modifier = Modifier.fillMaxSize(),
                color = MaterialTheme.colorScheme.background
            ) {
                Greeting3("Android")
            }
        }
    }
}

@Composable
private fun Greeting3(name: String, modifier: Modifier = Modifier) {

    var showLoad by remember {
        mutableStateOf(true)
    }
    Box {
        if (showLoad){
            //加载骨架屏
            AnimatedShimmerItem()
        }else{
            LazyColumn(){
                item{
                    val brush: Brush = Brush.linearGradient(
                        listOf(
                            Color.Red.copy(alpha = 0.6f),
                            Color.Red.copy(alpha = 0.2f),
                            Color.Red.copy(alpha = 0.6f),
                        ),
                        start = Offset(90f, 90f),
                    )
                    val roundedCornerShape = RoundedCornerShape(3.dp)
                    Text(text = "渐变的基础控件,自身使用offset造成偏移", fontSize = 12.sp,modifier= Modifier
                        .offset(x = 50.dp)
                        .background(
                            Color(0xFFC56565)
                        ))

                    Spacer(
                        modifier = Modifier
                            .height(20.dp)
                            .clip(roundedCornerShape)
                            .fillMaxWidth(0.7f)
                            .background(brush)
                    )

                }
//                item {
//                    LazyColumn(
//                        modifier = Modifier.nestedScroll(
//                            rememberNestedScrollInteropConnection()
//                        )
//                    ) {
//                        item {
//                            Text(
//                                text = "嵌套滑动",
//                                fontSize = 12.sp,
//                                modifier = Modifier
//                                    .offset(x = 50.dp)
//                                    .background(
//                                        Color(0xFFC56565)
//                                    )
//                            )
//                        }
//
//                    }
//                }

                item{
                    Text(text = "裁剪图片", fontSize = 12.sp,modifier=Modifier.background(
                        Color(0xFFC56565)
                    ))

                    Image(
                        painter = painterResource(id = R.drawable.bg1),
                        contentDescription = stringResource(id = R.string.barrier_free_content_description),
                        contentScale = ContentScale.Crop,
                        modifier = Modifier
                            .size(200.dp)
                            .border(
                                BorderStroke(2.dp, Color.Yellow),
                                CircleShape
                            )
                            .clip(RoundedCornerShape(16.dp))
                    )

                }

                item{
                    Text(text = "自定义图片合成的实现", fontSize = 12.sp,modifier=Modifier.background(
                        Color(0xFFC56565)
                    ))

                    val rainbowImage = ImageBitmap.imageResource(id = R.drawable.bg1)
                    val dogImage = ImageBitmap.imageResource(id = R.drawable.bg2)
                    val customPainter = remember {
                        OverlayImagePainter(dogImage, rainbowImage)
                    }
                    Image(
                        painter = customPainter,
                        contentDescription = null,
                        contentScale = ContentScale.Crop,
                        modifier = Modifier.wrapContentSize()
                    )

                }

                item{
                    Text(text = "自定义DrawScope的实现")
                    val image=ImageBitmap.imageResource(R.drawable.bg1)
                    Text(text = "自定义DrawScope的实现2",
                        modifier = Modifier
                            .wrapContentHeight()
                            .onSizeChanged {
                                Log.d(
                                    TAG,
                                    "自定义onSizeChanged的实现size: ${it.height}---${it.width}"
                                )

                            }
                            .drawBehind {

                                val canvasQuadrantSize = size / 2F
                                Log.d(
                                    TAG,
                                    "自定义DrawScope的实现size: ${size.height}---${size.width}"
                                )
                                Log.d(
                                    TAG,
                                    "自定义DrawScope的实现image: ${image.height}---${image.width}"
                                )
                                drawRect(
                                    color = Color(0xFFFF00FF),
                                    size = size
                                )
                                //负数：从右往左顶偏移，从下往上顶
                                drawImage(
                                    image = image,
                                    topLeft = Offset(-100f, -(image.height.toFloat() - 100))
                                )
                            }
                    )

                }

                item{
                    Text(text = "canvas 绘制圆圈,内部还是DrawScope")

                    Canvas(modifier = Modifier
                        .size(100.dp, 100.dp)
                        .background(Color(0xFF55E05C)), onDraw =  {
                        drawCircle(Color(0xFFFF0000),
                            radius = size.width/2-10, style = Stroke(width = 10f)
                        )

                        //绘制进度,0-360,绘制方向：左-下-右-上
                        drawArc(Color(0xFF105FE9),
                            size= Size(size.width-20, size.height-20),
                            topLeft = Offset(10f,10f),
                            startAngle = 0f,sweepAngle = 180f,useCenter = false, style = Stroke(width = 10f, cap = StrokeCap.Round)
                        )

//                    drawText(textLayoutResult = TextLayoutResult(TextLayoutInput(), multiParagraph = null, size = IntSize(100,100)),)
                    })



                }
                item{
                    Text(text = "canvas drawWithContent,定义绘制层级")

                    Box(modifier = Modifier
                        .size(100.dp, 100.dp)
                        .background(Color(0xFF55E05C))
                        .drawWithContent {
                            drawContent()
                            drawCircle(
                                Color(0xFF140202),
                                radius = 20f
                            )
                        }){
                        Box(modifier = Modifier
                            .size(100.dp, 100.dp)
                            .background(Color(0xFFE61066))) {

                        }
                    }



                }
                item{
                    Text(text = "canvas drawWithCache,绘制缓存，创建无限循环的透明动画")
                    val image=ImageBitmap.imageResource(R.drawable.bg1)
                    val alpha= animateFloatAsState(targetValue = 1f,
                        animationSpec = infiniteRepeatable(animation = tween(durationMillis = 2000, delayMillis = 3000)),

                        )
                    val alpha1= rememberInfiniteTransition().animateFloat(initialValue = 0f, targetValue = 1f, animationSpec = infiniteRepeatable(animation = tween(durationMillis = 2000)),
                    )


                    Text(text = "canvas drawWithCache,绘制缓存，创建无限循环的透明动画", modifier = Modifier.alpha(alpha.value))

                    Image(
                        modifier = Modifier.alpha(alpha1.value),
                        painter = painterResource(R.drawable.bg1),
                        contentDescription = null,
                    )
                    Box(modifier = Modifier
                        .size(100.dp, 100.dp)
//                     .background(Color(0xFF55E05C))
                        .drawWithCache() {
                            onDrawBehind {
                                drawImage(
                                    image = image,
                                    alpha = alpha1.value
                                )
                            }
                        })

                }

                item{
                    Text(text = "canvas 绘制波浪加载图片")
                    val image=ImageBitmap.imageResource(R.drawable.bg1)
                    WaveLoading(modifier = Modifier
                        .size(200.dp, 200.dp)
                        .background(Color(0xFF7CDA81)),
                        waveConfig = WaveConfig(), bitmap = image.asAndroidBitmap())

                }

                item{
                    Text(text = "测试内容改变动画")
                    testAnimatedContent()
                }

                item{
                    Text(text = "Transition 可管理一个或多个动画作为其子项，并在多个状态之间同时运行这些动画")
                    testUpdateTransition()
                }
                item{
                    Text(text = "阻尼动画")
                    SpringDemo()
                }

                item{
                    Text(text = "手动控制动画")
                    TargetBasedAnimationDemo()
                }

                item{
                    Text(text = "转化动画的数据类型")
                    AnimationVectorDemo()
                }

                item{
                    Text(text = "点击位移动画")
                    animationGesture()
                }

                item{
                    Text(text = "拖动粘性动画", modifier = Modifier
                        .size(500.dp, 100.dp)
                        .swipeToDismiss {
                            Log.d(TAG, "swipeToDismiss 扫描动画: ")
                        }
                        .background(Color(0xFF7CDA81)))

                }

                item{
                    Text(text = "展示点击收藏的显示隐藏动画")
                    ShowCollectClickAnimationButton()
                }


            }
        }
    }
    LaunchedEffect(true){
        delay(3000)
        showLoad = false
    }
}

@Composable
fun shimmerItem() {
    Box {
        Text(text = "骨架屏", fontSize = 12.sp,modifier= Modifier
            .offset(x = 50.dp)
            .background(
                Color(0xFFC56565)
            ))
        val shimmerColors = listOf<Color>(
            Color.LightGray.copy(0.6f),
            Color.LightGray.copy(0.2f),
            Color.LightGray.copy(0.6f)
        )
        val transition = rememberInfiniteTransition().animateFloat(
            initialValue = 0f,
            targetValue = 1000f,
            animationSpec = infiniteRepeatable(animation = tween(durationMillis = 1000, easing = FastOutSlowInEasing), repeatMode = RepeatMode.Reverse),
            label = ""
        )
        val brush: Brush = Brush.linearGradient(
            colors = shimmerColors,
            start = Offset.Zero,
            end = Offset(x = transition.value,y = transition.value)
        )
        val roundedCornerShape = RoundedCornerShape(3.dp)

        Column(modifier = Modifier
            .fillMaxWidth()
            .padding(all = 10.dp)) {
            Row(verticalAlignment = Alignment.CenterVertically) {
                Column {
                    repeat(5){
                        Spacer(modifier = Modifier.padding(spacerPadding))
                    }
                }
            }
        }

    }
}


/**
 *
 *拖动动画，粘性拖动
 */
fun Modifier. swipeToDismiss(
    onDismissed: () -> Unit
): Modifier = composed {
    val offsetX = remember { Animatable(0f) }
    pointerInput(Unit) {
        // Used to calculate fling decay.
        val decay = splineBasedDecay<Float>(this)
        // Use suspend functions for touch events and the Animatable.
        coroutineScope {
            while (true) {
                val velocityTracker = VelocityTracker()
                // Stop any ongoing animation.
                offsetX.stop()
                awaitPointerEventScope {
                    // Detect a touch down event.
                    val pointerId = awaitFirstDown().id

                    horizontalDrag(pointerId) { change ->
                        // Update the animation value with touch events.
                        launch {
                            offsetX.snapTo(
                                offsetX.value + change.positionChange().x
                            )
                        }
                        velocityTracker.addPosition(
                            change.uptimeMillis,
                            change.position
                        )
                    }
                }
                // No longer receiving touch events. Prepare the animation.
                val velocity = velocityTracker.calculateVelocity().x
                val targetOffsetX = decay.calculateTargetValue(
                    offsetX.value,
                    velocity
                )
                // The animation stops when it reaches the bounds.
                offsetX.updateBounds(
                    lowerBound = -size.width.toFloat(),
                    upperBound = size.width.toFloat()
                )
                launch {
                    if (targetOffsetX.absoluteValue <= size.width) {
                        // Not enough velocity; Slide back.
                        offsetX.animateTo(
                            targetValue = 0f,
                            initialVelocity = velocity
                        )
                    } else {
                        // The element was swiped away.
                        offsetX.animateDecay(velocity, decay)
                        onDismissed()
                    }
                }
            }
        }
    }
        .offset { IntOffset(offsetX.value.roundToInt(), 0) }
}

@Composable
fun animationGesture() {
    val offset = remember { Animatable(Offset(0f, 0f), Offset.VectorConverter) }
    Box(
        modifier = Modifier
            .fillMaxSize()
            .pointerInput(Unit) {
                coroutineScope {
                    while (true) {
                        // Detect a tap event and obtain its position.
                        awaitPointerEventScope {
                            val position = awaitFirstDown().position

                            launch {
                                // Animate to the tap position.
                                offset.animateTo(position)
                            }
                        }
                    }
                }
            }
    ) {
        Box(modifier = Modifier
            .offset { offset.value.toIntOffset() }
            .size(20.dp, 20.dp)
            .background(Color(0xFF1BEC14))
        )
    }
}

private fun Offset.toIntOffset() = IntOffset(x.roundToInt(), y.roundToInt())

@Composable
fun AnimationVectorDemo() {

    var animationValue by remember { mutableStateOf(false) }


    val targetSize = MySize(100.dp, 100.dp)
    val targetSize1 = MySize(50.dp, 50.dp)
    //和animateFloatAsState比较转化出MySize类型值的动画
    val animSize: MySize by animateValueAsState(
       if (animationValue) targetSize else targetSize1,
        typeConverter =TwoWayConverter(
            convertToVector = { size: MySize ->
                // Extract a float value from each of the `Dp` fields.
                Log.d("TAG", "AnimationVectorDemosize.width.value:${size.width.value}--- size.height.value:${size.height.value}")
                AnimationVector2D(size.width.value, size.height.value)

            },
            convertFromVector = { vector: AnimationVector2D ->
                Log.d("TAG", "AnimationVectorDemo: ${vector.v1.dp }----vector.v2.dp:${vector.v2.dp}")
                MySize(vector.v1.dp, vector.v2.dp)

            }
        ),
        animationSpec = infiniteRepeatable(animation = tween(durationMillis = 2000)),
        label = ""
    )

    Box(modifier = Modifier
        .size(animSize.width, animSize.height)
        .background(Color(0xFFF00D0D))
        .clickable {

            animationValue = !animationValue
        })

}
data class MySize(val width: Dp, val height: Dp)


@Composable
fun TargetBasedAnimationDemo() {

    val anim = remember {
        TargetBasedAnimation(
            animationSpec = tween(5000),
            typeConverter = Float.VectorConverter,
            initialValue = 100f,
            targetValue = 200f
        )
    }
    var animationValue by remember { mutableStateOf(0f) }

    var playTime by remember { mutableStateOf(0L) }
    Box(modifier = Modifier
        .size(animationValue.toInt().dp, animationValue.toInt().dp)
        .background(Color(0xFFF00D0D))
        .clickable {
        })
    LaunchedEffect(anim) {

        val startTime = withFrameNanos { it }
        Log.d("tgw", "TargetBasedAnimationDemos tartTime:$startTime ")
        do {
//            delay(1000)
            Log.d("tgw", "TargetBasedAnimationDemo withFrameNanos { it }:${withFrameNanos { it }} ")

            playTime = withFrameNanos { it } - startTime
            Log.d("tgw", "TargetBasedAnimationDemo playTime:$playTime ")

            animationValue = anim.getValueFromNanos(playTime)
            Log.d("tgw", "TargetBasedAnimationDemo:$animationValue ")


        } while (animationValue<200f)
    }
}


@OptIn(ExperimentalAnimationApi::class)
@Composable
private fun testAnimatedContent(){
    var expanded = remember { mutableStateOf(false) }
    Surface(
        color = Color(0xFF2A86CE),
        onClick = { expanded.value = !expanded.value }
    ) {
        AnimatedContent(
            targetState = expanded.value,
            transitionSpec = {
                fadeIn(animationSpec = tween(150, 150)) with
                        fadeOut(animationSpec = tween(150)) using
                        SizeTransform { initialSize, targetSize ->
                            if (targetState) {
                                Log.d(TAG, "testAnimatedContent:扩展变大的流程 ")
                                keyframes {
                                    // Expand horizontally first.
                                    //布局 150毫秒内扩展到1000, 100----之后慢慢收缩到正常布局
                                    //比如例子中表示expend过程持续时间为3000ms，在150ms前，高度保持不变，
                                    // 宽度逐渐增大，而在到达150ms之后，宽度到达目标值将不再变化，高度再逐渐增大
                                    IntSize(1000, initialSize.height) at 150
                                    durationMillis = 3000
                                }
                            } else {
                                keyframes {
                                    // Shrink vertically first.
                                    IntSize(1000, 1000) at 150
                                    durationMillis = 3000
                                }
                            }
                        }
            }, label = ""
        ) { targetExpanded ->
            if (targetExpanded) {
                Box(
                    Modifier
                        .size(200.dp, 400.dp)
                        .background(Color(0xFF80CF39))) {

                }
            } else {
                Box(
                    Modifier
                        .size(50.dp, 50.dp)
                        .background(Color(0xFFD31F8B))) {

                }
            }
        }
    }
}


enum class BoxState {
    Collapsed,
    Expanded
}
@Composable
private fun testUpdateTransition(){
    var currentState = remember { mutableStateOf(BoxState.Collapsed) }
    val transition = updateTransition(currentState, label = "")
    val size by transition.animateDp(transitionSpec = { tween(1000, easing = CubicBezierEasing(0.4f,0.0f,0.2f,1.0f)) }, label = "") {
      when(it.value){
          BoxState.Collapsed ->50.dp
          BoxState.Expanded ->200.dp
          else -> {50.dp}
      }
    }
    Box(modifier = Modifier
        .size(size, size)
        .background(Color(0xFFF00D0D))
        .clickable {
            currentState.value =
                if (currentState.value == BoxState.Collapsed) BoxState.Expanded else BoxState.Collapsed
        })
}





class OverlayImagePainter constructor(
    private val image: ImageBitmap,
    private val imageOverlay: ImageBitmap,
    private val srcOffset: IntOffset = IntOffset.Zero,
    private val srcSize: IntSize = IntSize(image.width, image.height),
    private val overlaySize: IntSize = IntSize(imageOverlay.width, imageOverlay.height)
) : Painter() {

    private val size: IntSize = validateSize(srcOffset, srcSize)
    override fun DrawScope.onDraw() {
        // draw the first image without any blend mode
        drawImage(
            image,
            srcOffset,
            srcSize,
            dstSize = IntSize(
                this@onDraw.size.width.roundToInt(),
                this@onDraw.size.height.roundToInt()
            )
        )
        // draw the second image with an Overlay blend mode to blend the two together
        drawImage(
            imageOverlay,
            srcOffset,
            overlaySize,
            dstSize = IntSize(
                this@onDraw.size.width.roundToInt(),
                this@onDraw.size.height.roundToInt()
            ),
            blendMode = BlendMode.Overlay
        )
    }

    /**
     * Return the dimension of the underlying [ImageBitmap] as it's intrinsic width and height
     */
    override val intrinsicSize: Size get() = size.toSize()

    private fun validateSize(srcOffset: IntOffset, srcSize: IntSize): IntSize {
        require(
            srcOffset.x >= 0 &&
                    srcOffset.y >= 0 &&
                    srcSize.width >= 0 &&
                    srcSize.height >= 0 &&
                    srcSize.width <= image.width &&
                    srcSize.height <= image.height
        )
        return srcSize
    }
}

@Preview(showBackground = true)
@Composable
fun GreetingPreview3() {
    Greeting3("Android")
}